from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator


class ScorePrediction(models.Model):
    """增强版成绩预测模型 - AI系统的核心"""

    # 预测状态选择
    PREDICTION_STATUS_CHOICES = [
        ('pending', '待验证'),
        ('accurate', '准确'),
        ('inaccurate', '不准确'),
        ('partially_accurate', '部分准确'),
    ]

    ALGORITHM_CHOICES = [
        ('xgboost', 'XGBoost'),
        ('lightgbm', 'LightGBM'),
        ('random_forest', '随机森林'),
        ('lstm', 'LSTM'),
        ('prophet', 'Prophet'),
        ('ensemble', '集成学习'),
    ]

    # 核心关联
    student = models.ForeignKey('users.Student', on_delete=models.CASCADE, related_name="score_predictions")
    subject = models.ForeignKey('score.Subject', on_delete=models.CASCADE, verbose_name="科目")

    # 预测结果体系
    predicted_score = models.FloatField(
        verbose_name="预测分数",
        validators=[MinValueValidator(0)]
    )
    confidence_interval_lower = models.FloatField(verbose_name="置信区间下限")
    confidence_interval_upper = models.FloatField(verbose_name="置信区间上限")
    confidence_level = models.FloatField(
        verbose_name="置信水平",
        validators=[MinValueValidator(0), MaxValueValidator(1)],
        default=0.95,
        help_text="0-1之间的置信概率"
    )

    # 预测详情
    prediction_date = models.DateField(verbose_name="预测日期", auto_now_add=True)
    target_exam_date = models.DateField(verbose_name="目标考试日期")
    exam = models.ForeignKey(
        'score.Exam',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name="关联考试",
        help_text="如果是针对特定考试的预测"
    )

    # 算法与模型信息
    algorithm_used = models.CharField(
        max_length=50,
        choices=ALGORITHM_CHOICES,
        verbose_name="使用算法"
    )
    model_version = models.CharField(max_length=100, verbose_name="模型版本", default="v1.0")
    training_data_size = models.IntegerField(verbose_name="训练数据量", default=0)

    # 详细特征存储
    input_features = models.JSONField(
        verbose_name="输入特征",
        help_text="模型输入的具体特征值",
        default=dict
    )
    feature_importance = models.JSONField(
        verbose_name="特征重要性",
        help_text="各特征对预测结果的贡献度",
        default=dict
    )

    # 预测分析与解释
    key_factors = models.JSONField(
        verbose_name="关键影响因素",
        help_text="影响预测结果的主要因素分析",
        default=list
    )
    risk_factors = models.JSONField(
        verbose_name="风险因素",
        help_text="可能导致成绩波动的风险点",
        default=list
    )

    # 实际结果验证（后续更新）
    actual_score = models.FloatField(
        verbose_name="实际分数",
        null=True,
        blank=True,
        validators=[MinValueValidator(0)]
    )
    prediction_error = models.FloatField(
        verbose_name="预测误差",
        null=True,
        blank=True,
        help_text="|预测分数-实际分数|"
    )
    status = models.CharField(
        max_length=20,
        choices=PREDICTION_STATUS_CHOICES,
        default='pending',
        verbose_name="预测状态"
    )

    # 性能指标
    model_accuracy = models.FloatField(
        verbose_name="模型准确率",
        null=True,
        blank=True,
        validators=[MinValueValidator(0), MaxValueValidator(1)]
    )
    prediction_quality_score = models.FloatField(
        verbose_name="预测质量评分",
        null=True,
        blank=True,
        validators=[MinValueValidator(0), MaxValueValidator(10)],
        help_text="综合评估预测质量，0-10分"
    )

    class Meta:
        verbose_name = "成绩预测"
        verbose_name_plural = "成绩预测分析"
        ordering = ['-prediction_date', 'student']
        indexes = [
            models.Index(fields=['student', 'prediction_date']),
            models.Index(fields=['status', 'prediction_quality_score']),
            models.Index(fields=['algorithm_used', 'model_version']),
        ]

    def __str__(self):
        accuracy = f" (误差: {self.prediction_error})" if self.prediction_error else ""
        return f"{self.student.name} - {self.subject.name}: {self.predicted_score}{accuracy}"

    def save(self, *args, **kwargs):
        """保存时自动计算相关指标"""
        # 如果有实际分数，计算预测误差
        if self.actual_score is not None:
            self.prediction_error = abs(self.predicted_score - self.actual_score)

            # 根据误差大小更新状态
            error_percentage = (self.prediction_error / self.subject.full_score) * 100
            if error_percentage <= 5:
                self.status = 'accurate'
                self.prediction_quality_score = 9.0
            elif error_percentage <= 10:
                self.status = 'partially_accurate'
                self.prediction_quality_score = 7.0
            else:
                self.status = 'inaccurate'
                self.prediction_quality_score = 5.0

        super().save(*args, **kwargs)

    @property
    def is_verified(self):
        """预测是否已被验证"""
        return self.actual_score is not None

    @property
    def score_trend(self):
        """成绩趋势分析"""
        # 这里可以实现与历史成绩的比较逻辑
        previous_predictions = ScorePrediction.objects.filter(
            student=self.student,
            subject=self.subject,
            prediction_date__lt=self.prediction_date
        ).order_by('-prediction_date')[:3]

        if len(previous_predictions) >= 2:
            recent_trend = self.predicted_score - previous_predictions[0].predicted_score
            if recent_trend > 2:
                return 'improving'
            elif recent_trend < -2:
                return 'declining'
        return 'stable'

    @property
    def risk_level(self):
        """风险评估"""
        if not self.risk_factors:
            return 'low'

        risk_score = len(self.risk_factors)
        confidence_width = self.confidence_interval_upper - self.confidence_interval_lower

        if confidence_width > 20:
            risk_score += 2
        elif confidence_width > 10:
            risk_score += 1

        if risk_score >= 4:
            return 'high'
        elif risk_score >= 2:
            return 'medium'
        return 'low'

    def update_with_actual_score(self, actual_score):
        """用实际分数更新预测结果"""
        self.actual_score = actual_score
        self.save()


class ImprovementRecommendation(models.Model):
    """改进建议模型"""
    prediction = models.ForeignKey(ScorePrediction, on_delete=models.CASCADE, related_name="recommendations")
    priority = models.IntegerField(verbose_name="优先级", choices=[(1, '高'), (2, '中'), (3, '低')])
    recommendation_type = models.CharField(max_length=50, verbose_name="建议类型")
    content = models.TextField(verbose_name="建议内容")
    expected_impact = models.FloatField(verbose_name="预期影响分数")
    time_required = models.IntegerField(verbose_name="所需时间(小时)")

    class Meta:
        verbose_name = "改进建议"
        verbose_name_plural = "改进建议"
        ordering = ['priority']
